package com.kevin.core.util;

import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.UnknownHostException;
import java.util.Properties;

import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;

import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.NoHttpResponseException;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.protocol.HttpContext;


public class MidService implements HttpRequestRetryHandler {
	private static final String CONFIG_FILE_NAME="midserver.properties";
	//最大连接数
	private static final Integer DEFAULT_MAX_TOTAL=null;
	//每个路由基础的连接数
	private static final Integer DEFAULT_MAX_PERROUTE=null;
	private static Properties conf=null;
	private static CloseableHttpClient httpClient=null;

	private static void config(HttpRequestBase httpRequestBase) {
		httpRequestBase.setHeader("User-Agent", "Mozilla/5.0");
		httpRequestBase.setHeader("Accept","text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
		httpRequestBase.setHeader("Accept-Language","zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3");// "en-US,en;q=0.5");
		httpRequestBase.setHeader("Accept-Charset","ISO-8859-1,utf-8,gbk,gb2312;q=0.7,*;q=0.7");

		// 配置请求的超时设置
		RequestConfig requestConfig = RequestConfig.custom()
				.setConnectionRequestTimeout(3000)
				.setConnectTimeout(3000)
				.setSocketTimeout(3000).build();
		httpRequestBase.setConfig(requestConfig);
	}
	
	static{
		conf=new Properties();
		try {
			conf.load(MidService.class.getClassLoader().getResourceAsStream(CONFIG_FILE_NAME));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	static{
		ConnectionSocketFactory plainsf = PlainConnectionSocketFactory.getSocketFactory();
		LayeredConnectionSocketFactory sslsf = SSLConnectionSocketFactory.getSocketFactory();
		Registry<ConnectionSocketFactory> registry = RegistryBuilder
				.<ConnectionSocketFactory> create()
				.register("http", plainsf)
				.register("https", sslsf)
				.build();
		Integer maxTotal = getInt("server.maxTotal",DEFAULT_MAX_TOTAL);
		Integer defaultMaxPerRoute = getInt("server.maxPerRoute",DEFAULT_MAX_PERROUTE);
		Integer serverCount = getInt("server.count");
		PoolingHttpClientConnectionManager connectionManager = 
				new PoolingHttpClientConnectionManager(registry);
		connectionManager.setMaxTotal(maxTotal);
		connectionManager.setDefaultMaxPerRoute(defaultMaxPerRoute);
		
		//Set MaxPerRoute
		for(int i=0;i<serverCount;i++){
			String protocol = get("server."+i+".protocol");
			String ip = get("server."+i+".ip");
			Integer port = getInt("server."+i+".port");
			Integer maxPerRoute = getInt("server."+i+".maxPerRoute",defaultMaxPerRoute);
			//String serviceIds = get("server."+i+".serviceIds");
			String url=protocol+"://"+ip+":"+port+"/";
			HttpHost httpHost = new HttpHost(url, port);
			connectionManager.setMaxPerRoute(new HttpRoute(httpHost),maxPerRoute);
		}
		
		//Build httpClient 
		httpClient = HttpClients.custom()
				.setConnectionManager(connectionManager)
				.setRetryHandler(new MidService()).build();
	}


	@Override
	public boolean retryRequest(IOException exception, int executionCount,
			HttpContext context) {
		// 如果已经重试了5次，就放弃
		if (executionCount >= 5) {
			return false;
		}
		// 如果服务器丢掉了连接，那么就重试
		if (exception instanceof NoHttpResponseException) {
			return true;
		}
		
		// 不要重试SSL握手异常
		if (exception instanceof SSLHandshakeException) {
			return false;
		}
		
		// 超时
		if (exception instanceof InterruptedIOException) {
			return false;
		}
		
		// 目标服务器不可达
		if (exception instanceof UnknownHostException) {
			return false;
		}
		
		// 连接被拒绝
		if (exception instanceof ConnectTimeoutException) {
			return false;
		}
		
		// ssl握手异常
		if (exception instanceof SSLException) {
			return false;
		}

		HttpClientContext clientContext = HttpClientContext.adapt(context);
		HttpRequest request = clientContext.getRequest();
		
		// 如果请求是幂等的，就再次尝试
		if (!(request instanceof HttpEntityEnclosingRequest)) {
			return true;
		}
		return false;
	}
	
	private static Integer getInt(String key){
		String value = get(key,null);
		return Integer.parseInt(value);
	}
	private static Integer getInt(String key,Integer defaultValue){
		String value = get(key, defaultValue.toString());
		return Integer.parseInt(value);
	}
	
	private static String get(String key){
		return conf.getProperty(key,null);
	}
	
	private static String get(String key,Object defaultValue){
		return conf.getProperty(key, defaultValue.toString());
	}

}
